<template>
	<view class="yh-dynamic-form">
		<uni-forms ref="FormRef" :model-value="formData" :rules="rules" :validate-trigger="validateTrigger" :err-show-type="errorShowType" :border="true">
			<uni-forms-item v-for="item in newColumns" :key="item.prop" :name="item.prop" :label="item.label" :required="item.required">
				<template #label>
					<view
						class="yh-dynamic-form-item-label-left yh-dynamic-form-item-label"
						:class="{ 'yh-dynamic-form-item-label-required': item.required }"
						v-if="item.type !== 'upload' && (item.labelPosition === 'left' || !item.labelPosition)"
						:style="{
							width: labelWidth ? ((parseInt(labelWidth) + '').length === labelWidth.length ? labelWidth + 'rpx' : labelWidth) : '140rpx',
						}"
					>
						{{ item.label || '' }}
						<slot :name="`${item.prop}_label`" />
						<!--	例如：<template #star_label>星级</template>	-->
					</view>
				</template>
				<view
					class="yh-dynamic-form-item"
					:class="
						item.prop +
						' ' +
						(item.type || 'input') +
						'-form-item ' +
						(item.formAlign === 'left' ? 'yh-dynamic-form-item-align-left' : 'yh-dynamic-form-item-align-right')
					"
				>
					<view
						class="yh-dynamic-form-item-label-top yh-dynamic-form-item-label"
						:class="{ 'yh-dynamic-form-item-label-required': item.required }"
						v-if="item.type !== 'upload' && item.labelPosition === 'top'"
					>
						{{ item.label || '' }}
						<slot :name="`${item.prop}_label`" />
						<!--	例如：<template #star_label>星级</template>	-->
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'input' || !item.type" @click="onClick(item, 'input', $event)">
						<uni-easyinput
							ref="InputRef"
							v-model="formData[item.prop]"
							placeholder-style="color: #c9cad7; font-size: 28rpx;"
							:trim="true"
							:clearable="item.clearable && false && false"
							:disabled="item.disabled"
							:type="item.mode || 'text'"
							:confirm-type="item.confirmType || 'done'"
							:placeholder="item.placeholder || `请输入${item.label}`"
							@input="onChange(item, 'input', $event)"
						/>
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'textarea'" @click="onClick(item, 'textarea', $event)">
						<uni-easyinput
							ref="TextareaRef"
							v-model="formData[item.prop]"
							type="textarea"
							placeholder-style="color: #c9cad7; font-size: 28rpx;"
							:maxlength="item.max || 500"
							:disabled="item.disabled"
							:confirm-type="item.confirmType || 'done'"
							:placeholder="item.placeholder || `请输入${item.label}`"
							:styles="{
								borderColor: 'transparent',
								backgroundColor: '#f8f9fb',
								disableColor: '#F4F5F7',
							}"
							@input="onChange(item, 'textarea', $event)"
						/>
						<view class="textarea-counter">{{ formData[item.prop] ? formData[item.prop].length || 0 : 0 }}/{{ item.max || 500 }}</view>
					</view>

					<view
						class="yh-dynamic-form-item-box"
						v-if="item.type === 'number'"
						@click="onClick(item, 'number', $event)"
						:class="{ hideNumberButton: item.hideNumberButton === true }"
					>
						<uni-number-box
							ref="NumberRef"
							v-model="formData[item.prop]"
							:width="item.width || 40"
							:disabled="item.disabled"
							:min="item.min || 0"
							:max="item.max || 9999999"
							:step="item.step || 1"
							@input="onChange(item, 'number', $event)"
						/>
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'numberInput'" @click="onClick(item, 'number', $event)">
						<uni-easyinput
							ref="NumberInputRef"
							v-model="formData[item.prop]"
							type="digit"
							placeholder-style="color: #c9cad7; font-size: 28rpx;"
							:trim="true"
							:clearable="item.clearable && false"
							:disabled="item.disabled"
							:confirm-type="item.confirmType || 'done'"
							:placeholder="item.placeholder || `请输入${item.label}`"
							@input="onChange(item, 'numberInput', $event)"
							@blur="onBlur(item, 'numberInput', $event)"
						/>
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'switch'" @click="onClick(item, 'switch', $event)">
						<switch
							ref="SwitchRef"
							color="#3d80ff"
							:checked="formData[item.prop]"
							:disabled="item.disabled"
							@change="onChange(item, 'switch', $event)"
						/>
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'radio'" @click="onClick(item, 'radio', $event)">
						<uni-data-checkbox
							ref="RadioRef"
							v-model="formData[item.prop]"
							:mode="item.mode || 'default'"
							:localdata="item.options"
							:disabled="item.disabled"
							@change="onChange(item, 'radio', $event)"
						/>
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'checkbox'" @click="onClick(item, 'checkbox', $event)">
						<uni-data-checkbox
							ref="CheckboxRef"
							v-model="formData[item.prop]"
							multiple
							:mode="item.mode || 'default'"
							:localdata="item.options"
							:disabled="item.disabled"
							:map="{ text: 'label', value: 'value' }"
							@change="onChange(item, 'checkbox', $event)"
						/>
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'picker'" @click="onClick(item, 'picker', $event)">
						<picker
							ref="PickerRef"
							:value="activePickerData[item.prop]"
							:mode="item.mode || 'selector'"
							:range-key="item.mode === 'region' ? undefined : item.labelKey || 'label'"
							:range="item.options"
							:start="item.min"
							:end="item.max"
							:disabled="item.disabled"
							@change="onChange(item, 'picker', $event)"
							@cancel="onClosed(item, 'picker', $event)"
							@columnchange="onColumnChange(item, 'picker', $event)"
						>
							<view class="picker-text picker-value" v-if="formData[item.prop] || formData[item.prop] === 0">
								<view v-if="item.mode === 'selector'">
									{{ item.options && activePickerData[item.prop] ? item.options[activePickerData[item.prop]][item.labelKey || 'label'] : '' }}
								</view>
								<view v-if="item.mode === 'multiSelector'">
									{{
										item.options && activePickerData[item.prop]
											? activePickerData[item.prop].map((e, i) => item.options[i][e][item.labelKey || 'label']).join('/')
											: ''
									}}
								</view>
								<view v-if="['time', 'date'].includes(item.mode) || item.mode === undefined">
									{{ activePickerData[item.prop] }}
								</view>
								<view v-if="item.mode === 'region'">{{ activePickerData[item.prop] ? activePickerData[item.prop].join('/') : '' }}</view>
							</view>
							<view class="picker-text placeholder" v-else>{{ item.placeholder || `请选择${item.label}` }}</view>
						</picker>
						<uni-icons class="yh-dynamic-form-item-icon" type="right" size="14" color="#41424C" />
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'select'" @click="onClick(item, 'select', $event)">
						<uni-data-select
							ref="SelectRef"
							v-model="formData[item.prop]"
							empty-tips="暂无数据"
							:clear="item.clearable && false"
							:localdata="item.options"
							:disabled="item.disabled"
							:placeholder="item.placeholder || `请选择${item.label}`"
							@change="onChange(item, 'select', $event)"
						/>
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'cascader'" @click="onClick(item, 'cascader', $event)">
						<uni-data-picker
							ref="CascaderRef"
							v-model="formData[item.prop]"
							:popup-title="`请选择${item.label}`"
							:clear-icon="item.clearable && false"
							:localdata="item.options"
							:readonly="item.disabled"
							:placeholder="item.placeholder || `请选择${item.label}`"
							:map="{ text: 'label', value: 'value' }"
							@change="onChange(item, 'cascader', $event)"
							@popupclosed="onClosed(item, 'cascader', $event)"
						/>
						<uni-icons class="yh-dynamic-form-item-icon" type="right" size="14" color="#41424C" />
					</view>

					<view
						class="yh-dynamic-form-item-box"
						:class="{ dateValueText: formData[item.prop] }"
						v-if="item.type === 'date'"
						@click="onClick(item, 'date', $event)"
					>
						<uni-datetime-picker
							ref="DateRef"
							v-model="formData[item.prop]"
							:type="item.mode ? item.mode : 'date'"
							:clear-icon="item.clearable && false"
							:disabled="item.disabled"
							:hide-second="item.hideSecond"
							:start="item.min || ''"
							:end="item.max || ''"
							:placeholder="item.placeholder || `请选择${item.label}`"
							:start-placeholder="item.placeholder ? item.placeholder[0] : `开始日期`"
							:end-placeholder="item.placeholder ? item.placeholder[1] : `结束日期`"
							@change="onChange(item, 'date', $event)"
							@maskClick="onClosed(item, 'date', $event)"
						/>
						<uni-icons class="yh-dynamic-form-item-icon" type="right" size="14" color="#41424C" />
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'tree'" @click="onClick(item, 'tree', $event)">
						<view class="tree-text tree-value" v-if="formData[item.prop] || formData[item.prop] === 0">
							{{ activeTreeData[item.prop] ? activeTreeData[item.prop][item.config ? item.config.labelKey || 'label' : 'label'] : '' }}
						</view>
						<view class="tree-text placeholder" v-else>{{ item.placeholder || `请选择${item.label}` }}</view>
						<uni-icons class="yh-dynamic-form-item-icon" type="right" size="14" color="#41424C" />
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'upload'" @click="onClick(item, 'upload', $event)">
						<upload-file
							v-model="formData[item.prop]"
							:title="item.placeholder || `${item.label || '附件'}(不超过${item.limit || 5}个，单个文件小于${item.size || 50}M)`"
							:mode="item.mode || 'file'"
							:required="item.required"
							:limit="item.limit || 5"
							:size="item.size || 50"
							:duration="item.duration || 30"
							:disabled="item.disabled"
							:file-type-list="item.fileTypeList"
							:file-name-length="item.fileNameLength || 100"
						/>
					</view>

					<view class="yh-dynamic-form-item-box" v-if="item.type === 'slot'" @click="onClick(item, 'slot', $event)">
						<slot :name="item.prop" />
					</view>
				</view>
			</uni-forms-item>
		</uni-forms>

		<next-tree
			ref="NextTreeRef"
			themeColor="#3d80ff"
			:label-key="activeFormItem.config && activeFormItem.config.labelKey ? activeFormItem.config.labelKey : 'label'"
			:value-key="activeFormItem.config && activeFormItem.config.valueKey ? activeFormItem.config.valueKey : 'value'"
			:children-key="activeFormItem.config && activeFormItem.config.childrenKey ? activeFormItem.config.childrenKey : 'children'"
			:disabled-key="activeFormItem.config && activeFormItem.config.disabledKey ? activeFormItem.config.disabledKey : 'disabled'"
			:placeholder="activeFormItem.config && activeFormItem.config.placeholder ? activeFormItem.config.placeholder : '请输入后搜索'"
			:if-search="activeFormItem.config ? (activeFormItem.config.ifSearch === undefined ? true : activeFormItem.config.ifSearch) : true"
			:select-parent="activeFormItem.config ? (activeFormItem.config.selectParent === undefined ? true : activeFormItem.config.selectParent) : true"
			:treeData="activeFormItem.options || []"
			@cancel="onClosed(activeFormItem, 'tree', $event)"
			@confirm="onChange(activeFormItem, 'tree', $event)"
		/>
	</view>
</template>

<script>
import { deepClone, checkTreeData } from './index';
import NextTree from './components/next-tree/components/next-tree/next-tree.vue';
import UploadFile from './components/uploadFile.vue';

/**
 * 注意事项
 * 	- 动态修改columns表单项中的字段必须使用this.$set(this.columns[0], 'disabled', false)这种形式
 */
export default {
	options: {
		styleIsolation: 'shared',
	},
	components: { NextTree, UploadFile },
	props: {
		// 表单项标题宽度（每个汉字28rpx，112rpx容纳4个汉字）
		labelWidth: {
			type: String,
			default: '140rpx',
		},
		// 表单校验触发时机（bind/blur/submit）
		validateTrigger: {
			type: String,
			default: 'blur',
		},
		// 表单校验错误提示方式（undertext/toast/modal）
		errorShowType: {
			type: String,
			default: 'undertext',
		},
		// 用于执行requestOptions方法的接口请求头
		requestHeader: {
			type: Object,
			default: () => {},
		},
		/**
		 * 表单项配置
		 * 	- prop: 字段名
		 * 	- label: 标题
		 * 	- labelPosition: 表单项标题位置（left默认、top）
		 * 	- formAlign: 表单项对齐方式（left、right默认）
		 * 	- type: 表单项类型（见下述）
		 * 	- options: 选项（radio、checkbox、picker、select、cascader、tree有效）{label: '选项名称', value: '选项值', disabled: 是否禁用, children: 级联子项}
		 * 	- mode: 组件模式（input、numberInput、radio、checkbox、picker、date、upload有效）
		 * 			input：text文本键盘、textarea多行文本键盘、password密码键盘、number数字键盘、digit小数点数字键盘、idcard身份证键盘
		 * 			numberInput：integer整数、decimal小数
		 * 			radio/checkbox：default默认、list列表、button按钮、tag标签
		 * 			picker：selector默认、multiSelector多列、time时间、date日期、region省市区
		 * 			date：date日期、daterange日期范围、datetime日期时间、timetimerange日期时间范围
		 * 			upload：file文件上传、image图片上传、video视频上传
		 * 	- hidden: 是否隐藏
		 * 	- disabled: 是否禁用
		 * 	- required: 是否必填
		 * 	- clearable: 是否可清空
		 * 	- placeholder: 占位文本（范围选择时传数组）
		 * 	- labelKey: options中用于显示的字段（radio、checkbox、picker、select、cascader有效）
		 * 	- valueKey: options中用于取值的字段（radio、checkbox、picker、select、cascader有效）
		 * 	- childrenKey: options中用于子级的字段（radio、checkbox、picker、select、cascader有效）
		 * 	- confirmType: 键盘右下角按钮的文字（input、numberInput、textarea有效）
		 * 	- hideSecond: 是否隐藏秒（date有效）
		 * 	- step: 步长（number有效）
		 * 	- width: 输入框宽度（number有效，传数字）
		 * 	- hideNumberButton: 是否隐藏加减按钮（number有效）
		 * 	- max: 最大值/最大长度/最大数量/最晚日期/最晚时间
		 * 	- min: 最小值/最小长度/最小数量/最早日期/最早时间
		 * 	- config：树形组件配置对象（tree有效）（支持字段：labelKey、valueKey、childrenKey、disabledKey、ifSearch、selectParent、placeholder）
		 * 	- limit: 文件最大上传数量（upload有效）
		 * 	- size: 文件最大文件大小（upload有效）
		 * 	- duration: 视频最长持续时长（upload->mode:video有效）
		 * 	- fileTypeList: 允许上传文件类型（upload有效）
		 * 	- fileNameLength: 最大文件名长度（upload有效）
		 * 	- pattern: 正则表达式（input有效。由于微信的限制，必须是字符串形式，\需要转义为\\，例如匹配手机号：'^1[345789]\\d{9}$'）
		 * 	- validateFunction: 自定义表单校验函数（参考地址：https://uniapp.dcloud.net.cn/component/uniui/uni-forms.html#validatefunction-自定义校验规则使用说明）
		 *****************************************************************************************
		 * 	表单项类型
		 * 	- input: 输入框
		 * 	- textarea: 文本域
		 * 	- number: 数字步进器
		 * 	- numberInput: 数字输入框
		 * 	- switch: 开关
		 * 	- radio: 单选框
		 * 	- checkbox: 多选框
		 * 	- picker: 数据选择器
		 * 	- select: 下拉选择器
		 * 	- cascader: 级联选择器
		 * 	- date: 日期选择器
		 * 	- tree: 树形选择器
		 * 	- upload: 文件上传
		 * 	- slot: 插槽
		 */
		columns: {
			type: Array,
			default() {
				return [];
			},
		},
	},
	data() {
		return {
			rules: {},
			formData: {},
			newColumns: [],
			targetLabelFieldMapping: {
				radio: 'text',
				checkbox: 'label',
				select: 'text',
				cascader: 'label',
				tree: 'label',
			},
			// 所有switch开关
			switchProps: [],
			// 所有radio单选框
			radioProps: [],
			// 所有checkbox复选框
			checkboxProps: [],
			// 所有select选择器
			selectProps: [],
			// 所有cascader选择器
			cascaderProps: [],
			// 所有date选择器
			dateProps: [],
			// 所有tree选择器
			treeProps: [],
			// 当前操作的表单项
			activeFormItem: {},
			// 所有tree选择器选中的数据
			activeTreeData: {},
			// 所有picker选择器选中的数据
			activePickerData: {},
		};
	},
	computed: {
		newFormData() {
			const formData = deepClone(this.formData);
			this.checkboxProps.forEach((prop) => {
				if (!formData?.[prop]?.length) {
					delete formData[prop];
				}
			});
			return formData;
		},
	},
	watch: {
		columns: {
			handler() {
				this.switchProps = [];
				this.radioProps = [];
				this.checkboxProps = [];
				this.selectProps = [];
				this.cascaderProps = [];
				this.dateProps = [];
				this.treeProps = [];
				const newColumns = deepClone(this.columns);
				newColumns.forEach((item) => {
					if (item.props) {
						for (const k in item.props) {
							this.$set(item, k, item.props[k]);
						}
						delete item.props;
					}
					item.label = item.title || item.label;
					item.type = item.formType || item.type;
					if (item.type === 'switch') {
						this.switchProps.push(item.prop);
						if (!this.formData[item.prop] && item.required) this.$set(this.formData, item.prop, false);
					}
					if (item.type === 'radio') {
						this.radioProps.push(item.prop);
					}
					if (item.type === 'checkbox') {
						this.checkboxProps.push(item.prop);
						if (!this.formData[item.prop]) this.$set(this.formData, item.prop, []);
					}
					if (item.type === 'select') {
						this.selectProps.push(item.prop);
					}
					if (item.type === 'cascader') {
						this.cascaderProps.push(item.prop);
					}
					if (item.type === 'date') {
						this.dateProps.push(item.prop);
					}
					if (item.type === 'tree') {
						this.treeProps.push(item.prop);
						if (item.config) {
							for (const k in item.config) {
								if (item.config[k] === 'true') item.config[k] = true;
								if (item.config[k] === 'false') item.config[k] = false;
							}
						}
					}
					if (['radio', 'checkbox', 'select', 'cascader', 'tree'].includes(item.type)) {
						if (!item.options) item.options = [];
						item.options = this.handleOptions(
							item.options,
							[
								{ sourceField: item.labelKey || 'label', targetField: this.targetLabelFieldMapping[item.type] },
								{ sourceField: item.valueKey || 'value', targetField: 'value' },
								{ sourceField: item.childrenKey || 'children', targetField: 'children' },
								{ sourceField: 'disabled', targetField: 'disable' },
							],
							item.childrenKey
						);
					}
				});
				this.newColumns = newColumns.filter((item) => !item.hidden);
				this.handleRules();
			},
			deep: true,
			immediate: true,
		},
	},
	methods: {
		// 请求获取radio、checkbox、select、cascader、tree的options数据（仅支持接口返回的数据结构为data数组）
		// props指定请求哪些表单项的接口（例如['gender', 'city', 'dept']），不传则请求所有接口
		async requestOptions(props = undefined, labelKey = 'name', valueKey = 'id', childrenKey = 'children') {
			if (!props) props = [...this.radioProps, ...this.checkboxProps, ...this.selectProps, ...this.cascaderProps, ...this.treeProps];
			if (!Array.isArray(props)) return;
			const itemList = this.columns.filter((item) => props.includes(item.prop));
			const requestList = [];
			itemList.forEach((item) => {
				if (item?.effect?.fetch) {
					requestList.push(
						new Promise((resolve, reject) => {
							const api = item.effect.fetch;
							uni.request({
								url: api.action,
								method: api.method,
								data: api.query,
								header: {
									token: `Bearer ${uni.getStorageSync('token')}`,
									'project-id': uni.getStorageSync('projectId'),
									'tenant-id': uni.getStorageSync('tenantId'),
									...api.header,
									...this.requestHeader,
								},
								success: (res) => {
									resolve({
										prop: item.prop,
										...res.data,
									});
								},
								fail: (err) => {
									reject({
										prop: item.prop,
										...err.data,
									});
								},
							});
						})
					);
				}
			});
			const apiResultList = await Promise.allSettled(requestList);
			apiResultList.forEach((result) => {
				if (result.status === 'fulfilled') {
					let columnIndex = -1;
					const value = result.value;
					const columnItem = this.newColumns.find((item, index) => {
						if (item.prop === value?.prop) columnIndex = index;
						return item.prop === value?.prop;
					});
					if (columnItem && columnIndex !== -1) {
						this.$set(
							this.newColumns[columnIndex],
							'options',
							this.handleOptions(
								value?.data || [],
								[
									{
										sourceField: columnItem?.effect?.fetch?.data?.labelKey || labelKey,
										targetField: this.targetLabelFieldMapping[columnItem.type] || 'text',
									},
									{ sourceField: columnItem?.effect?.fetch?.data?.valueKey || valueKey, targetField: 'value' },
								],
								childrenKey
							)
						);
					}
				}
			});
		},
		// 设置表单数据，props不传则修改所有表单数据，传入字符串或数组则只修改对应表单数据
		setFormData(data, props) {
			const columnsProps = this.columns.map((item) => item.prop);
			const cloneData = deepClone(data);
			// 如果那么不存在，则将同时存在于data、existingData中所有的属性重新赋值
			if (!props) {
				Object.keys(data || {}).forEach((key) => {
					if (columnsProps.includes(key)) {
						this.formData[key] = cloneData[key];
					}
				});
			} else if (typeof props === 'string') {
				// 如果props为string那么不存在，则将存在于existingData中对应属性重新赋值
				if (columnsProps.includes(props)) {
					this.formData[props] = cloneData[props];
				}
			} else if (Array.isArray(props)) {
				// 如果props为array，则将同时存在于existingData,props中对应属性重新赋值
				props.forEach((prop) => {
					if (columnsProps.includes(prop)) {
						this.formData[prop] = cloneData[prop];
					}
				});
			}
		},
		// 获取表单数据
		getFormData() {
			return deepClone(this.newFormData);
		},
		// 校验表单
		async validate() {
			let result = {
				valid: false,
				error: [],
				formData: this.newFormData,
			};
			this.clearValidate();
			await this.$refs?.FormRef?.validate((err) => {
				result = {
					valid: !err,
					error: err,
					formData: this.newFormData,
				};
			});
			return result;
		},
		// 清除校验，参数为字符串或数组，不传清除全部
		clearValidate(props) {
			this.$refs?.FormRef?.clearValidate(props);
		},
		// 打开选择器（select、cascader、date）
		open(prop) {
			const item = this.newColumns.find((item) => item.prop === prop);
			if (item.type === 'select') {
				const instance = this.$refs?.SelectRef?.[this.selectProps.findIndex((prop) => prop === item.prop)];
				instance?.toggleSelector();
				// if (instance?.showSelector !== undefined) instance.showSelector = true;
			}
			if (item.type === 'cascader') {
				const instance = this.$refs?.CascaderRef?.[this.cascaderProps.findIndex((prop) => prop === item.prop)];
				instance?.isOpened ? instance?.hide() : instance?.show();
				// instance?.show();
			}
			if (item.type === 'date') {
				const instance = this.$refs?.DateRef?.[this.dateProps.findIndex((prop) => prop === item.prop)] || {};
				instance.pickerVisible ? instance?.close() : instance?.show();
				instance.pickerVisible = !instance?.pickerVisible;
				// instance?.show();
			}
		},

		onClick(item, type, event) {
			if (['select', 'cascader'].includes(type)) {
				if (type === 'select' && this.$refs?.SelectRef?.[this.selectProps.findIndex((prop) => prop === item.prop)]?.showSelector) {
					this.$emit('click', {
						item,
						type,
						prop: item.prop,
						data: event,
						formData: this.newFormData,
					});
				}
				if (type === 'cascader' && this.$refs?.CascaderRef?.[this.cascaderProps.findIndex((prop) => prop === item.prop)]?.isOpened) {
					this.$emit('click', {
						item,
						type,
						prop: item.prop,
						data: event,
						formData: this.newFormData,
					});
				}
			} else if (type === 'tree') {
				this.activeFormItem = item;
				if (item?.options?.length) {
					item.options = checkTreeData(item.options, this.formData[item.prop], 'checked', item?.config?.valueKey, item?.config?.childrenKey);
				}
				if (!item?.disabled) this.$refs.NextTreeRef.showTree = true;
			} else {
				this.$emit('click', {
					item,
					type,
					prop: item.prop,
					data: event,
					formData: this.newFormData,
				});
			}
		},
		onChange(item, type, event) {
			if (type === 'switch') {
				event = event?.detail?.value || false;
				this.$set(this.formData, item.prop, event);
			}
			if (type === 'picker') {
				if (item?.mode === 'region') {
					event = event?.detail || {};
					delete event?.postcode;
					this.activePickerData[item.prop] = event?.value;
				} else {
					event = event?.detail?.value || '';
					this.activePickerData[item.prop] = event;
				}
				if (item?.mode === 'selector' || item?.mode === undefined) {
					this.activePickerData[item.prop] = event;
					event = item.options?.[event]?.[item.valueKey || 'value'];
				}
				if (item?.mode === 'multiSelector') {
					this.activePickerData[item.prop] = event;
					const label = [];
					const value = [];
					event?.forEach((e, i) => {
						label.push(item.options?.[i]?.[e]?.[item.labelKey || 'label']);
						value.push(item.options?.[i]?.[e]?.[item.valueKey || 'value']);
					});
					event = value;
				}
				this.$set(this.formData, item.prop, event);
			}
			if (type === 'radio') {
				event = event?.detail?.value || '';
			}
			if (type === 'checkbox') {
				event = event?.detail?.value || [];
			}
			if (type === 'cascader') {
				event = event?.detail?.value?.map((item) => item.value) || [];
				this.formData[item.prop] = event;
			}
			if (type === 'numberInput') {
				let num = (event || '').trim();
				if (item.mode === 'integer') {
					num = num.replace(/[^0-9]/g, '');
				} else {
					num = num.replace(/[^0-9.]/g, '');
				}
				// 只保留第一个小数点
				num = num.replace(/(\..*?)\..*/g, '$1');
				// 去掉开头无效的0
				num = num.replace(/^0+(\d)/, '$1');
				// 如果以小数点开头则自动补0
				num = num.replace(/^\.([0-9]+)/, '0.$1');
				this.$nextTick(() => this.$set(this.formData, item.prop, num));
			}
			if (type === 'tree') {
				const active = event?.length ? event[0] : {};
				event = active[item?.config?.valueKey || 'value'] || '';
				this.activeTreeData[item.prop] = active;
				this.$set(this.formData, item.prop, event);
			}
			this.$nextTick(() => {
				this.$emit('change', {
					item,
					type,
					prop: item.prop,
					data: event,
					formData: this.newFormData,
				});
			});
		},
		onClosed(item, type, event) {
			this.$emit('closed', {
				item,
				type,
				prop: item.prop,
				data: event,
				formData: this.newFormData,
			});
			// if (type === 'date' && !this.newFormData[item.prop]) {
			// 	const instance = this.$refs?.DateRef?.[this.dateProps.findIndex((prop) => prop === item.prop)];
			// 	instance?.clear();
			// 	delete this.formData[item.prop];
			// }
		},
		onBlur(item, type, event) {
			if (type === 'numberInput') {
				let num = (event?.detail?.value || '').trim();
				const originNum = num;
				// 去掉小数点末尾无效的0
				num = num.replace(/(\.\d*?)0+$/g, '$1');
				// 去掉末尾无效的小数点
				num = num.replace(/\.$/, '');
				if (item.min && num && +num < +item.min) num = item.min;
				if (item.max && num && +num > +item.max) num = item.max;
				if (num !== originNum) {
					this.$nextTick(() => {
						this.$set(this.formData, item.prop, num + '');
						this.$emit('change', {
							item,
							type,
							prop: item.prop,
							data: event,
							formData: this.newFormData,
						});
					});
				}
			}
		},
		onColumnChange(item, type, event) {
			const columnIndex = event?.detail?.column;
			const valueIndex = event?.detail?.value;
			let value = undefined;
			if (valueIndex || valueIndex === 0) {
				value = item.options?.[columnIndex]?.[valueIndex];
			}
			this.$nextTick(() => {
				this.$emit('pickerColumnChange', {
					item,
					type,
					prop: item.prop,
					data: value?.[item?.valueKey || 'value'],
					formData: this.newFormData,
				});
			});
		},
		handleRules() {
			let rules = {};
			this.newColumns.forEach((item) => {
				if (!rules[item.prop]) {
					rules[item.prop] = {
						rules: [],
					};
				}
				if (item.required) {
					rules[item.prop].rules.push({
						required: true,
						errorMessage: `${item.label}不能为空`,
					});
				}
				if (item.max && item.type !== 'numberInput') {
					rules[item.prop].rules.push({
						maxLength: item.max,
						errorMessage: item.type === 'checkbox' ? `${item.label}最多选择${item.max}项` : `${item.label}长度最大为${item.max}`,
					});
				}
				if (item.min && item.type !== 'numberInput') {
					rules[item.prop].rules.push({
						minLength: item.min,
						errorMessage: item.type === 'checkbox' ? `${item.label}最少选择${item.min}项` : `${item.label}长度最小为${item.min}`,
					});
				}
				if (item.pattern && (item.type === undefined || item.type === 'input')) {
					rules[item.prop].rules.push({
						pattern: item.pattern,
						errorMessage: `${item.label}格式不正确`,
					});
				}
				if (item.validateFunction) {
					rules[item.prop].rules.push({
						validateFunction: item.validateFunction,
					});
				}
			});
			this.rules = rules;
		},
		handleOptions(tree, fieldMapping, childrenKey = 'children') {
			return tree.map((node) => {
				const transformedNode = { ...node };

				fieldMapping.forEach((rule) => {
					if (node.hasOwnProperty(rule.sourceField)) {
						transformedNode[rule.targetField] = node[rule.sourceField];
					}
				});

				// 处理原 childrenKey 并创建新的 children
				if (node[childrenKey]) {
					transformedNode[childrenKey] = this.handleOptions(node[childrenKey], fieldMapping, childrenKey);
					transformedNode['children'] = this.handleOptions(node[childrenKey], fieldMapping, childrenKey);
				}

				return transformedNode;
			});
		},
	},
	created() {
		this.$nextTick(() => {
			this.requestOptions();
		});
	},
};
</script>

<style scoped lang="scss">
.yh-dynamic-form {
	.yh-dynamic-form-item-label {
		color: #6c6d7a;
		font-size: 28rpx;

		&.yh-dynamic-form-item-label-required {
			&::before {
				content: '*';
				color: #f56c6c;
			}
		}
	}

	/deep/ .uni-forms-item {
		min-height: 68rpx;
		align-items: center;

		.yh-dynamic-form-item {
			position: relative;

			.checklist-group {
				gap: 30rpx;
				padding: 10rpx 0;

				.checklist-box {
					margin: 0;
				}
			}

			.checklist-text {
				color: #2f2f46;
				font-size: 28rpx;
			}

			.uni-select,
			.input-value-border,
			.uni-date-x--border {
				border: none;
				padding: 0;
			}

			.uni-select__input-text,
			.selected-area {
				display: block;
				margin-right: 10rpx;
			}

			.yh-dynamic-form-item-icon {
				right: -4rpx;
				bottom: 11rpx;
				position: absolute;
			}

			&.input-form-item,
			&.number-form-item,
			&.numberInput-form-item,
			&.picker-form-item,
			&.select-form-item,
			&.cascader-form-item,
			&.date-form-item,
			&.tree-form-item {
				input,
				.tree-value,
				.picker-value,
				.text-color,
				.dateValueText .uni-date__x-input {
					color: #12172f !important;
				}

				.uni-select__input-text {
					color: #12172f;
				}
			}

			&.input-form-item,
			&.numberInput-form-item,
			&.select-form-item {
				.is-input-border {
					border: none;
					padding: 0;
				}

				.is-disabled,
				.uni-select--disabled {
					border-color: transparent !important;
					background-color: transparent !important;
				}

				input {
					padding: 0 !important;
				}
			}

			&.number-form-item {
				.hideNumberButton {
					.uni-numbox-btns {
						display: none;
					}

					.uni-numbox__value {
						background-color: transparent !important;
						margin: 0;
					}
				}
			}

			&.textarea-form-item {
				.textarea-counter {
					color: #989cab;
					font-size: 24rpx;
					line-height: 36rpx;
					text-align: right;
					margin-top: -4rpx;
				}
			}

			&.picker-form-item {
				.picker-text {
					height: 68rpx;
					line-height: 68rpx;
					font-size: 28rpx;
					margin-right: 36rpx;
				}

				.placeholder {
					color: #c9cad7;
				}
			}

			&.select-form-item {
				.uni-select__input-placeholder {
					color: #c9cad7;
					font-size: 28rpx;
				}

				.uni-icons {
					margin-right: -3rpx;
					color: #4c4e58 !important;
				}

				.uni-popper__arrow_bottom {
					left: auto;
					right: 10%;
				}
			}

			&.cascader-form-item {
				.uni-data-tree-input {
					.selected-area {
						margin-right: 36rpx;
					}

					.selected-list {
						.selected-item {
							max-width: 260rpx;
							display: flex;
							white-space: normal;

							.text-color {
								overflow: hidden;
								display: -webkit-box;
								word-break: break-all;
								-webkit-line-clamp: 1;
								-webkit-box-orient: vertical;
							}
						}
					}
				}

				.uni-data-tree-dialog {
					.selected-list {
						justify-content: flex-start;

						.selected-item {
							max-width: 260rpx;
							overflow: hidden;
							word-break: break-word;
							text-overflow: ellipsis;
						}
					}

					.pickerview--item text {
						overflow: hidden;
						white-space: nowrap;
						text-overflow: ellipsis;
					}
				}

				.placeholder {
					color: #c9cad7;
					font-size: 28rpx;
				}

				.arrow-area {
					display: none;
					width: 14px;
					margin-right: -3rpx;

					.input-arrow {
						width: 6px;
						height: 6px;
					}
				}
			}

			&.date-form-item {
				.uni-date__x-input {
					color: #c9cad7;
					font-size: 28rpx;
					margin-right: 36rpx;
				}

				.uni-date-range {
					.uni-date__x-input {
						text-align: center;
						margin-right: 0;
					}
				}

				.uni-date-editor--x__disabled {
					opacity: 1;
				}

				.icon-calendar .uni-icons {
					display: none;
				}
			}

			&.tree-form-item {
				.tree-text {
					height: 68rpx;
					line-height: 68rpx;
					font-size: 28rpx;
					margin-right: 36rpx;
				}

				.placeholder {
					color: #c9cad7;
				}
			}

			&.yh-dynamic-form-item-align-left {
				&.input-form-item input,
				&.numberInput-form-item input,
				&.select-form-item input,
				.selected-area,
				.uni-select__input-text,
				.uni-date__x-input,
				.picker-text,
				.tree-value,
				.placeholder {
					text-align: left;
				}

				&.switch-form-item .yh-dynamic-form-item-box,
				.checklist-group,
				.uni-numbox,
				.selected-list {
					text-align: start;
					justify-content: flex-start;
				}
			}

			&.yh-dynamic-form-item-align-right {
				&.input-form-item input,
				&.numberInput-form-item input,
				&.select-form-item input,
				.selected-area,
				.uni-select__input-text,
				.uni-date__x-input,
				.picker-text,
				.tree-value,
				.placeholder {
					text-align: right;
				}

				&.switch-form-item .yh-dynamic-form-item-box,
				.checklist-group,
				.uni-numbox,
				.selected-list {
					text-align: end;
					justify-content: flex-end;
				}
			}
		}

		.uni-forms-item__content {
			position: static;

			.uni-forms-item__error {
				position: absolute;
				top: auto;
				left: auto;
				right: 0;
				bottom: 4rpx;
			}
		}

		&.uni-forms-item--border {
			border-color: #f0f2f4;
		}
	}

	/deep/ .next-tree {
		.next-tree-cnt {
			top: 10vh;
			overflow: hidden;
			border-radius: 24rpx 24rpx 0 0;

			.next-tree-view {
				padding-bottom: 60rpx;

				.next-tree-view-sc {
					height: 100%;
				}
			}
		}
	}
}
</style>

<style lang="scss">
.text-overflow-ellipsis {
	overflow: hidden;
	display: -webkit-box;
	word-break: break-all;
	-webkit-line-clamp: 1;
	-webkit-box-orient: vertical;
}
</style>
